<script setup>
import { ref, h, inject } from 'vue'
import { CloudUpload, Document, Download, AlertCircle } from '@vicons/ionicons5'
import { useMessage, useDialog } from 'naive-ui'
import { useMainStore } from '../pinia.js'

const mainStore = useMainStore()
const hljs = inject('hljs')
const message = useMessage()
const dialog = useDialog()

const emit = defineEmits(['message'])

const uploadLoading = ref(false)
const batchPending = ref(0)
const batchSuccess = ref(0)
const batchFailure = ref(0)
// 使用store中的processedFiles替代本地状态
// const processedFiles = ref([])
const showDffModal = ref(false)
const selectedDffInfo = ref(null)
const pdfPageCount = ref(1) // 删除最后页数设置，默认为1页

// TRF缓存管理相关状态
const showTrfCacheModal = ref(false)
const cacheStatsLoading = ref(false)
const cacheStats = ref(null)
const cacheCleanLoading = ref(false)
const cacheCleanForm = ref({
  maxAge: '',
  maxFiles: '',
  specificFiles: []
})

const processLoadingVisible = ref(false)
const processLoadingOrder = ref('')
const processOrderQueue = ref([])
const processStatus = ref('running')
const orderStatuses = ref({})
const processingQueue = ref([])
const processingBusy = ref(false)
const processingProgress = ref({})

const processNext = async () => {
  if (processingQueue.value.length === 0) {
    processingBusy.value = false
    processLoadingOrder.value = ''
    if (batchPending.value === 0) processStatus.value = 'success'
    return
  }
  processingBusy.value = true
  const f = processingQueue.value[0]
  const ord = f.dffInfo?.detail?.headers?.orderNo || f.originalName?.replace(/\.[^/.]+$/, '') || ''
  processLoadingOrder.value = ord
  if (ord) orderStatuses.value[ord] = 'running'
  try {
    await callTrfApi(f, {
      onStep: (phase) => {
        const prog = processingProgress.value[f.fileId]
        if (!prog) return
        const setStatus = (idx, status) => { prog.statuses[idx] = status }
        switch (phase) {
          case 'csv:start':
            setStatus(1, 'process')
            orderStatuses.value[ord] = 'CSV已生成'
            break
          case 'csv:done':
            setStatus(1, 'finish')
            orderStatuses.value[ord] = 'CSV已生成'
            break
          case 'trf:start':
            setStatus(2, 'process')
            orderStatuses.value[ord] = 'TRF识别中'
            break
          case 'trf:done':
            setStatus(2, 'finish')
            setStatus(3, 'finish')
            orderStatuses.value[ord] = 'TRF识别完成'
            break
          case 'gpo:start':
            setStatus(4, 'process')
            orderStatuses.value[ord] = '推送GPO中'
            break
          case 'gpo:done':
            setStatus(4, 'finish')
            setStatus(5, 'finish')
            orderStatuses.value[ord] = 'GPO已更新'
            break
          default:
            orderStatuses.value[ord] = '处理中'
        }
      }
    })
    const updated = mainStore.processedFiles.find(ff => ff.fileId === f.fileId)
    const ok = updated?.gpoUpdateResult && updated.gpoUpdateResult.status === 200
    if (ord) {
      if (ok) {
        orderStatuses.value[ord] = 'GPO已更新'
      } else {
        orderStatuses.value[ord] = '流程失败'
        const prog = processingProgress.value[f.fileId]
        if (prog) {
          // 标记当前或最后一步错误
          const idx = prog.statuses.findIndex(s => s === 'process')
          if (idx >= 0) prog.statuses[idx] = 'error'
          else prog.statuses[5] = 'error'
        }
      }
    }
  } catch (e) {
    if (ord) {
      orderStatuses.value[ord] = '流程失败'
      const prog = processingProgress.value[f.fileId]
      if (prog) {
        const idx = prog.statuses.findIndex(s => s === 'process')
        if (idx >= 0) prog.statuses[idx] = 'error'
        else prog.statuses[1] = 'error'
      }
    }
  }
  processingQueue.value.shift()
  await processNext()
}

const enqueueProcessing = async (files) => {
  for (const f of files) {
    if (f.productDffResponse && f.productDffResponse.length > 0 && f.processedFilePath) {
      processingQueue.value.push(f)
      const ord = f.dffInfo?.detail?.headers?.orderNo || f.originalName?.replace(/\.[^/.]+$/, '') || ''
      if (ord) orderStatuses.value[ord] = orderStatuses.value[ord] || '待开始'
      if (!processLoadingOrder.value && ord) processLoadingOrder.value = ord
      const labels = ['PDF处理', 'CSV已生成', 'TRF识别', 'TRF识别完成', '推送GPO中', 'GPO已更新']
      const statuses = ['finish', 'wait', 'wait', 'wait', 'wait', 'wait']
      processingProgress.value[f.fileId] = { orderNo: ord, labels, statuses }
    }
  }
  processLoadingVisible.value = true
  if (!processingBusy.value) await processNext()
}

const ensureProgressEntry = (f) => {
  const ord = f.dffInfo?.detail?.headers?.orderNo || f.originalName?.replace(/\.[^/.]+$/, '') || ''
  if (ord) orderStatuses.value[ord] = orderStatuses.value[ord] || '待开始'
  if (!processingProgress.value[f.fileId]) {
    const labels = ['PDF处理', 'CSV已生成', 'TRF识别', 'TRF识别完成', '推送GPO中', 'GPO已更新']
    const statuses = ['finish', 'wait', 'wait', 'wait', 'wait', 'wait']
    processingProgress.value[f.fileId] = { orderNo: ord, labels, statuses }
  }
}

const runWithProgress = async (file) => {
  ensureProgressEntry(file)
  processLoadingVisible.value = true
  const ord = processingProgress.value[file.fileId]?.orderNo || ''
  await callTrfApi(file, {
    onStep: (phase) => {
      const prog = processingProgress.value[file.fileId]
      if (!prog) return
      const setStatus = (idx, status) => { prog.statuses[idx] = status }
      switch (phase) {
        case 'csv:start':
          setStatus(1, 'process')
          orderStatuses.value[ord] = 'CSV已生成'
          break
        case 'csv:done':
          setStatus(1, 'finish')
          orderStatuses.value[ord] = 'CSV已生成'
          break
        case 'trf:start':
          setStatus(2, 'process')
          orderStatuses.value[ord] = 'TRF识别'
          break
        case 'trf:done':
          setStatus(2, 'finish')
          setStatus(3, 'finish')
          orderStatuses.value[ord] = 'TRF识别完成'
          break
        case 'gpo:start':
          setStatus(4, 'process')
          orderStatuses.value[ord] = '推送GPO中'
          break
        case 'gpo:done':
          setStatus(4, 'finish')
          setStatus(5, 'finish')
          orderStatuses.value[ord] = 'GPO已更新'
          break
        default:
          orderStatuses.value[ord] = '处理中'
      }
    }
  })
}

// 构建 FieldCode -> DisplayName 映射
const buildDisplayNameMap = (csvContent) => {
  try {
    if (!csvContent || typeof csvContent !== 'string') return {}
    const lines = csvContent.split(/\r?\n/).filter(l => l.trim().length > 0)
    if (lines.length <= 1) return {}
    const parseCsvLine = (line) => {
      const result = []
      let cur = ''
      let inQuotes = false
      for (let i = 0; i < line.length; i++) {
        const ch = line[i]
        if (inQuotes) {
          if (ch === '"') {
            if (line[i + 1] === '"') { cur += '"'; i++ } else { inQuotes = false }
          } else {
            cur += ch
          }
        } else {
          if (ch === '"') { inQuotes = true }
          else if (ch === ',') { result.push(cur); cur = '' }
          else { cur += ch }
        }
      }
      result.push(cur)
      return result
    }
    const header = parseCsvLine(lines[0]).map(h => h.trim().toLowerCase())
    const codeIdx = header.findIndex(h => h === 'fieldcode')
    const nameIdx = header.findIndex(h => h === 'displayname')
    if (codeIdx === -1 || nameIdx === -1) return {}
    const map = {}
    for (let i = 1; i < lines.length; i++) {
      const cols = parseCsvLine(lines[i])
      const code = (cols[codeIdx] || '').trim()
      const name = (cols[nameIdx] || '').trim()
      if (code) map[code] = name || code
    }
    return map
  } catch (e) {
    return {}
  }
}

// 支持的文件类型 - 与后端保持一致
const acceptedFileTypes = [
  // PDF文档
  '.pdf',
  'application/pdf',
  // Word文档
  '.doc',
  '.docx', 
  'application/msword',
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  // Excel表格
  '.xls',
  '.xlsx',
  'application/vnd.ms-excel',
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  // PowerPoint演示文稿
  '.ppt',
  '.pptx',
  'application/vnd.ms-powerpoint',
  'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  // 文本文件
  '.txt',
  '.rtf',
  'text/plain',
  'text/rtf',
  'application/rtf',
  // 图片文件
  '.jpg',
  '.jpeg',
  '.png',
  '.gif',
  '.bmp',
  '.tiff',
  'image/jpeg',
  'image/png',
  'image/gif',
  'image/bmp',
  'image/tiff'
].join(',')

// 文件名校验函数
const validateFileName = (fileName) => {
  // 移除文件扩展名，只校验文件名部分
  const nameWithoutExt = fileName.replace(/\.[^/.]+$/, '')
  
  // order格式：前四位大写字母 + 中间10位数字 + 后两位大写字母
  const orderPattern = /^[A-Z]{4}\d{10}[A-Z]{2}$/
  
  // enquiry格式：前四位大写字母 + 中间10位数字 + 最后一位大写E
  const enquiryPattern = /^[A-Z]{4}\d{10}E$/
  
  const isOrderFormat = orderPattern.test(nameWithoutExt)
  const isEnquiryFormat = enquiryPattern.test(nameWithoutExt)
  
  return {
    isValid: isOrderFormat || isEnquiryFormat,
    format: isOrderFormat ? 'order' : (isEnquiryFormat ? 'enquiry' : null),
    fileName: nameWithoutExt
  }
}

// TRF to GPO功能
  const trfToGpo = async (file) => {
  try {
    // 设置加载状态
    mainStore.updateFileStatus(file.fileId, { trfToGpoLoading: true })
    
    // 获取orderNo
    const orderNo = file.dffInfo?.detail?.headers?.orderNo || file.originalName.replace(/\.[^/.]+$/, '')
    
    // 由于 updateFileStatus 会替换 processedFiles 中的对象，这里需要确保拿到最新的文件对象
    let currentFile = file
    if (!currentFile.trfApiResult) {
      const fresh = mainStore.processedFiles.find(f => f.fileId === file.fileId)
      if (fresh && fresh.trfApiResult) {
        currentFile = fresh
      } else {
        emit('message', 'error', '没有TRF API结果数据', { duration: 0, closable: true })
        return
      }
    }
    
    // 调用后端API将TRF数据推送到GPO
    const response = await fetch('/api/file/trf-to-gpo', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: JSON.stringify({
        orderNo,
        trfResult: currentFile.trfApiResult,
        objectType: currentFile.dffInfo?.type || 'order'
      })
    })
    
    if (!response.ok) {
      throw new Error(`HTTP错误: ${response.status} ${response.statusText}`)
    }
    
    const result = await response.json()

    const updateResult = result?.data?.updateResult
    const gpoRequestData = result?.data?.gpoRequestData
    // 将更新结果保存到文件状态，用于内联指示显示
    mainStore.updateFileStatus(file.fileId, { gpoUpdateResult: updateResult, gpoRequestData })
    if (updateResult && updateResult.status === 200) {
      console.log('TRF to GPO成功:', updateResult)
    } else {
      console.error('TRF to GPO未成功:', { updateResult, result })
    }
    return updateResult
    
  } catch (error) {
    console.error('TRF to GPO错误:', error)
    return null
  } finally {
    // 清除加载状态
    mainStore.updateFileStatus(file.fileId, { trfToGpoLoading: false })
  }
}

// 上传前重复检测并确认覆盖
const checkFileBeforeUpload = async (fileName) => {
  try {
    const resp = await fetch('/api/file/check-file', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: JSON.stringify({ fileName })
    })
    if (!resp.ok) {
      return { exists: false }
    }
    const result = await resp.json()
    const info = result?.data?.duplicates?.[fileName]
    return { exists: !!info?.exists, count: info?.count || 0, records: info?.records || [] }
  } catch (e) {
    console.warn('检查重复失败，忽略并继续上传:', e)
    return { exists: false }
  }
}

const handleFileUpload = async ({ file, onFinish, onError }) => {
  try {
    if (batchPending.value === 0) {
      mainStore.clearProcessedFiles()
      batchSuccess.value = 0
      batchFailure.value = 0
      uploadLoading.value = true
      processOrderQueue.value = []
      processStatus.value = 'running'
      processLoadingVisible.value = true
      processLoadingOrder.value = ''
    }
    batchPending.value += 1
    
    // 文件名校验
    const validation = validateFileName(file.name)
    if (validation.isValid) {
      processOrderQueue.value.push(validation.fileName)
      orderStatuses.value[validation.fileName] = 'pending'
    } else {
      const fn = file.name.replace(/\.[^/.]+$/, '')
      processOrderQueue.value.push(fn)
      orderStatuses.value[fn] = 'pending'
    }
    if (!validation.isValid) {
      const errorMessage = `文件名不正确！支持的格式：Order No./Enquiry No.`
      
      emit('message', 'error', errorMessage)
      batchFailure.value += 1
      onError()
      batchPending.value -= 1
      if (batchPending.value <= 0) {
        uploadLoading.value = false
      }
      return
    }
    
    // 上传前重复检测
    const duplicateInfo = await checkFileBeforeUpload(file.name)
    let overwrite = false
    if (duplicateInfo.exists) {
      // 提示用户确认覆盖
      const userConfirmed = await new Promise((resolve) => {
        dialog.warning({
          title: '检测到已处理文件',
          content: `文件 “${file.name}” 已处理过（${duplicateInfo.count} 次）。是否重新处理并覆盖原内容？`,
          positiveText: '覆盖处理',
          negativeText: '取消',
          closable: true,
          onPositiveClick: () => resolve(true),
          onNegativeClick: () => resolve(false),
          onClose: () => resolve(false),
          onEsc: () => resolve(false)
        })
      })
      if (!userConfirmed) {
        emit('message', 'warning', '已取消上传：未选择覆盖处理')
        batchFailure.value += 1
        onError()
        batchPending.value -= 1
        if (batchPending.value <= 0) {
          uploadLoading.value = false
          const ok = batchSuccess.value
          const fail = batchFailure.value
          let msg = `成功处理 ${ok} 个文件`
          if (fail > 0) msg += `，${fail} 个文件处理失败`
          emit('message', fail > 0 ? 'warning' : 'success', msg)
        }
        return
      }
      overwrite = true
    }

    const formData = new FormData()
    formData.append('files', file.file)
    formData.append('pdfPageCount', pdfPageCount.value) // 新增：传递页数参数
    // 传递统计所需用户信息（如果可用）
    formData.append('userName', mainStore.displayUsername || '')
    formData.append('userLocation', mainStore.userInfo?.location || '')
    formData.append('overwrite', overwrite ? 'true' : 'false')
    
    const response = await fetch('/api/file/upload', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: formData
    })
    
    let parsed
    try {
      parsed = await response.json()
    } catch {}
    if (!response.ok) {
      const msg = parsed?.message || `HTTP错误: ${response.status} ${response.statusText}`
      emit('message', 'error', '文件上传失败: ' + msg)
      batchFailure.value += 1
      onError()
      batchPending.value -= 1
      if (batchPending.value <= 0) {
        uploadLoading.value = false
        const ok = batchSuccess.value
        const fail = batchFailure.value
        let msg = `成功处理 ${ok} 个文件`
        if (fail > 0) msg += `，${fail} 个文件处理失败`
        emit('message', fail > 0 ? 'warning' : 'success', msg)
      }
      return
    }
    const result = parsed
    
    if (result.success) {
      // 处理单个文件或多个文件的响应
      const files = Array.isArray(result.data) ? result.data : [result.data]
      
      const processedFilesWithDff = []
      for (const fileData of files) {
        try {
          const dffTemplateInfo = await queryDffTemplateForFile(validation, fileData.originalName)
          processedFilesWithDff.push({
            ...fileData,
            dffInfo: fileData.dffInfo,
            powerBiStats: fileData.powerBiStats,
            dffTemplateInfo: dffTemplateInfo.dffFields,
            productDffResponse: dffTemplateInfo.productDffResponse,
            samplesDffResponse: dffTemplateInfo.samplesDffResponse
          })
        } catch (dffError) {
          console.warn(`文件 ${fileData.originalName} DFF模板查询失败:`, dffError)
          processedFilesWithDff.push({
            ...fileData,
            dffInfo: fileData.dffInfo,
            powerBiStats: fileData.powerBiStats,
            dffTemplateInfo: null,
            productDffResponse: null,
            samplesDffResponse: null
          })
        }
      }
      
      mainStore.processedFiles.push(...processedFilesWithDff)
      processedFilesWithDff.forEach(f => ensureProgressEntry(f))
      // 组合提示：包含PBI统计状态
      const total = processedFilesWithDff.length
      const statsOk = processedFilesWithDff.filter(f => f.powerBiStats && f.powerBiStats.success).length
      const statsFail = processedFilesWithDff.filter(f => f.powerBiStats && f.powerBiStats.success === false).length
      const statsMissing = total - statsOk - statsFail
      // let extraMsg = ''
      // if (statsOk === total) extraMsg = '，已发送PBI统计成功'
      // else if (statsOk > 0 && statsFail > 0) extraMsg = '，部分PBI统计失败'
      // else if (statsFail === total) extraMsg = '，PBI统计全部失败'
      // else if (statsMissing === total) extraMsg = ''
      // else extraMsg = '，PBI统计状态不完整'
      // emit('message', 'success', result.message + '，已自动获取DFF模板信息' + extraMsg)
      onFinish()
      batchSuccess.value += 1
      batchPending.value -= 1
      if (batchPending.value <= 0) {
        uploadLoading.value = false
      }
      if (!mainStore.isAdmin) {
        await enqueueProcessing(processedFilesWithDff)
      }
    } else {
      emit('message', 'error', result.message || '文件处理失败')
      onError()
      batchFailure.value += 1
      batchPending.value -= 1
      if (batchPending.value <= 0) {
        uploadLoading.value = false
        const ok = batchSuccess.value
        const fail = batchFailure.value
        let msg = `成功处理 ${ok} 个文件`
        if (fail > 0) msg += `，${fail} 个文件处理失败`
        emit('message', fail > 0 ? 'warning' : 'success', msg)
      }
    }
  } catch (error) {
    console.error('文件上传错误:', error)
    emit('message', 'error', '文件上传失败: ' + error.message)
    onError()
    batchFailure.value += 1
    batchPending.value -= 1
    if (batchPending.value <= 0) {
      uploadLoading.value = false
      const ok = batchSuccess.value
      const fail = batchFailure.value
      let msg = `成功处理 ${ok} 个文件`
      if (fail > 0) msg += `，${fail} 个文件处理失败`
      emit('message', fail > 0 ? 'warning' : 'success', msg)
    }
  } finally {
    
  }
}

const downloadFile = (file) => {
  const link = document.createElement('a')
  link.href = file.downloadUrl
  link.download = file.processedFileName
  document.body.appendChild(link)
  link.click()
  document.body.removeChild(link)
}



const clearProcessedFiles = async () => {
  try {
    // 调用后端API清理文件
    const response = await fetch('/api/file/clear-all', {
      method: 'DELETE',
      headers: {
        'Content-Type': 'application/json'
      }
    })
    
    const result = await response.json()
    
    if (result.success) {
      // 清理成功，清空前端列表
      mainStore.clearProcessedFiles()
    } else {
      console.error('文件清理失败:', result.message)
    }
  } catch (error) {
    console.error('调用清理API失败:', error)
    // 即使API调用失败，也清空前端列表
    mainStore.clearProcessedFiles()
  }
}

const getFileIcon = (fileName) => {
  const ext = fileName.split('.').pop().toLowerCase()
  switch (ext) {
    case 'pdf':
      return Document
    default:
      return Document
  }
}

const formatFileSize = (bytes) => {
  if (bytes === 0) return '0 Bytes'
  const k = 1024
  const sizes = ['Bytes', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const showDffInfo = (dffInfo, dffTemplateInfo = null, productDffResponse = null, samplesDffResponse = null) => {
  // 如果有DFF模板信息，将其合并到DFF信息中显示
  if (dffTemplateInfo) {
    selectedDffInfo.value = {
      ...dffInfo,
      templateInfo: dffTemplateInfo,
      productDffResponse: productDffResponse,
      samplesDffResponse: samplesDffResponse
    }
  } else {
    selectedDffInfo.value = dffInfo
  }
  showDffModal.value = true
}

// DFF模板查询功能（用于自动调用）
const queryDffTemplateForFile = async (validation, originalFileName) => {
  // 确定objectType和productLineCode
  const objectType = validation.format === 'order' ? 'Order' : 'Enquiry'
  const objectNo = validation.fileName // 使用完整的文件名（不含扩展名）
  const productLineCode = 'HL' // 固定使用HL作为产品线代码
    
  const response = await fetch('/api/file/query-dff-template', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${mainStore.authToken}`
    },
    body: JSON.stringify({
      objectType,
      objectNo,
      productLineCode
    })
  })
  
  if (!response.ok) {
    throw new Error(`HTTP错误: ${response.status} ${response.statusText}`)
  }
  
  const result = await response.json()
  
  if (result.success) {
    return result.data
  } else {
    throw new Error(result.message || 'DFF模板查询失败')
  }
}

const formatDffData = (data) => {
  return JSON.stringify(data, null, 2)
}

// 将值格式化为非 JSON 的可读文本
const formatPlainValue = (val) => {
  if (val === null || val === undefined) return '无'
  if (Array.isArray(val)) return `数组(${val.length})`
  if (typeof val === 'object') return `对象(${Object.keys(val).length}项)`
  if (typeof val === 'boolean') return val ? 'true' : 'false'
  return String(val)
}

// 显示DFF错误详情
const showDffError = (error, fileName) => {
  selectedDffInfo.value = {
    title: `DFF查询错误详情 - ${fileName}`,
    type: 'dff-error',
    fileName: fileName,
    error: error
  }
  showDffModal.value = true
}

// 显示PBI统计数据
const showPbiStats = (powerBiStats, fileName) => {
  selectedDffInfo.value = {
    type: 'pbi-stats',
    fileName: fileName,
    content: powerBiStats
  }
  showDffModal.value = true
}

// TRF API调用功能
const callTrfApi = async (file, opts = {}) => {
  try {
    // 设置加载状态
    mainStore.updateFileStatus(file.fileId, { trfApiLoading: true })
    
  // 获取orderNo
  const orderNo = file.dffInfo?.detail?.headers?.orderNo || file.originalName.replace(/\.[^/.]+$/, '')
  
  // 跳过缓存检查：总是重新处理TRF API
    
    // 如果没有缓存，继续正常的TRF API调用流程
    console.log('TRF API调用:', orderNo)
    
    // 获取产品DFF数据
    const productDffData = file.productDffResponse || []
    
    if (!productDffData || productDffData.length === 0) {
      emit('message', 'warning', '没有找到产品DFF数据')
      return
    }
    
    if (!file.processedFilePath) {
      emit('message', 'warning', '没有找到处理后的文件路径')
      return
    }
    
    // 首先生成CSV内容
    opts?.onStep && opts.onStep('csv:start')
    const csvResponse = await fetch('/api/file/generate-csv', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: JSON.stringify({
        orderNo,
        productDffData
      })
    })
    
    if (!csvResponse.ok) {
      throw new Error(`CSV生成失败: ${csvResponse.status} ${csvResponse.statusText}`)
    }
    
    const csvResult = await csvResponse.json()
    
    if (!csvResult.success) {
      throw new Error(csvResult.message || 'CSV生成失败')
    }
    
    // 调用TRF API
    opts?.onStep && opts.onStep('csv:done')
    opts?.onStep && opts.onStep('trf:start')
    const trfResponse = await fetch('/api/file/call-trf-api', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: JSON.stringify({
        docFilePath: file.processedFilePath,
        csvContent: csvResult.data.csvContent,
        orderNo
      })
    })
    
    if (!trfResponse.ok) {
      throw new Error(`TRF API调用失败: ${trfResponse.status} ${trfResponse.statusText}`)
    }
    
    const trfResult = await trfResponse.json()
    
    if (trfResult.success) {
      // 保存TRF API结果到文件对象
      // 从返回的数据结构中提取实际的结果数据
      const displayNameMap = buildDisplayNameMap(csvResult.data.csvContent)
      const trfRequestData = trfResult?.data?.trfRequestData
      mainStore.updateFileStatus(file.fileId, { trfApiResult: trfResult, trfDisplayNameMap: displayNameMap, trfRequestData })
      
      // emit('message', 'success', 'TRF API调用成功！结果已保存')

      // 继续执行：自动推送到GPO
      opts?.onStep && opts.onStep('trf:done')
      opts?.onStep && opts.onStep('gpo:start')
      await trfToGpo(file)
      opts?.onStep && opts.onStep('gpo:done')
    } else {
      emit('message', 'error', trfResult.message || 'TRF API调用失败')
    }
    
  } catch (error) {
    console.error('TRF API调用错误:', error)
    emit('message', 'error', 'TRF API调用失败: ' + error.message)
  } finally {
    mainStore.updateFileStatus(file.fileId, { trfApiLoading: false })
  }
}

// 显示TRF API结果
const showTrfApiResult = (file) => {
  // 使用最新的文件对象，避免旧引用导致误提示
  const currentFile = mainStore.processedFiles.find(f => f.fileId === file.fileId) || file
  const result = currentFile.trfApiResult
  
  // 仅在未成功时提示，没有结果或明确失败
  if (!result) {
    emit('message', 'warning', '没有TRF API结果数据')
    return
  }
  if (result.success === false) {
    emit('message', 'error', result.message || 'TRF API调用失败')
    return
  }
  
  // 格式化显示TRF API结果
  let displayContent = ''
  
  if (result.data && result.data.files && result.data.files.length > 0) {
    const fileResult = result.data.files[0]
    const extractedData = fileResult.result || {}
    const displayNameMap = currentFile.trfDisplayNameMap || {}
    
    displayContent = `TRF处理结果:

  File Name: ${fileResult.file_name}
  Processing Status: ${fileResult.status}
  Skill Code: ${fileResult.skill_code}
  Skill Name: ${fileResult.skill_name}

提取的字段数据:

${Object.entries(extractedData).map(([key, value]) => `${displayNameMap[key] ? `${displayNameMap[key]} (${key})` : key}: ${value || '(空)'}`).join('\n')}

完整响应数据:

  ${JSON.stringify(result, null, 2)}`
    } else {
      displayContent = `TRF API处理结果:

  ${JSON.stringify(result, null, 2)}`
    }
  
  // 创建一个新的模态框来显示TRF API结果
  selectedDffInfo.value = {
    title: `TRF 识别结果 - ${currentFile.originalName}`,
    content: displayContent,
    type: 'trf-result'
  }
  showDffModal.value = true
}

const showTrfRequest = (file) => {
  const currentFile = mainStore.processedFiles.find(f => f.fileId === file.fileId) || file
  const req = currentFile.trfRequestData
  if (!req) {
    emit('message', 'warning', '没有TRF请求体')
    return
  }
  selectedDffInfo.value = {
    title: `TRF 请求体 - ${currentFile.originalName}`,
    content: JSON.stringify(req, null, 2),
    type: 'trf-request'
  }
  showDffModal.value = true
}
const showGpoRequest = (file) => {
  const currentFile = mainStore.processedFiles.find(f => f.fileId === file.fileId) || file
  const req = currentFile.gpoRequestData
  if (!req) {
    emit('message', 'warning', '没有GPO请求体')
    return
  }
  selectedDffInfo.value = {
    title: `GPO 请求体 - ${currentFile.originalName}`,
    content: JSON.stringify(req, null, 2),
    type: 'gpo-request'
  }
  showDffModal.value = true
}

// CSV下载功能
const downloadCsv = async (file) => {
  try {
    // 获取orderNo
    const orderNo = file.dffInfo?.detail?.headers?.orderNo || file.originalName.replace(/\.[^/.]+$/, '')
    
    // 获取产品DFF数据
    const productDffData = file.productDffResponse || []
    
    if (!productDffData || productDffData.length === 0) {
      emit('message', 'warning', '没有找到产品DFF数据')
      return
    }
    
    const response = await fetch('/api/file/generate-csv', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${mainStore.authToken}`
      },
      body: JSON.stringify({
        orderNo,
        productDffData
      })
    })
    
    if (!response.ok) {
      throw new Error(`HTTP错误: ${response.status} ${response.statusText}`)
    }
    
    const result = await response.json()
    
    if (result.success) {
      // 创建下载链接
      const blob = new Blob([result.data.csvContent], { type: 'text/csv;charset=utf-8;' })
      const link = document.createElement('a')
      const url = URL.createObjectURL(blob)
      link.setAttribute('href', url)
      link.setAttribute('download', result.data.fileName)
      link.style.visibility = 'hidden'
      document.body.appendChild(link)
      link.click()
      document.body.removeChild(link)
      URL.revokeObjectURL(url)
      
      emit('message', 'success', 'CSV文件下载成功')
    } else {
      emit('message', 'error', result.message || 'CSV生成失败')
    }
  } catch (error) {
    console.error('CSV下载错误:', error)
    emit('message', 'error', 'CSV下载失败: ' + error.message)
  }
}



</script>

<template>
  <n-grid x-gap="12" :cols="1">
    <!-- 文件上传区域 -->
    <n-gi class="main-part">
      <n-card title="文件上传处理" size="large">
        <template #header-extra>
          <n-tag type="info">支持: PDF, Word, Excel, 文本, 图片等</n-tag>
        </template>
        
        <n-spin :show="uploadLoading">
          <n-space align="center" style="margin-bottom: 8px;">
            <n-text depth="3" style="font-size: 12px;">删除PDF末尾</n-text>
            <n-input-number 
              v-model:value="pdfPageCount" 
              :min="0" 
              :max="50" 
              size="small"
              placeholder="页数"
              style="width: 120px;"
            >
              <template #suffix>页</template>
            </n-input-number>
            <n-tooltip placement="top">
              <template #trigger>
                <n-tag size="small" type="info">说明</n-tag>
              </template>
              <div style="font-size: 12px; line-height: 1.4;">
                默认1；最多50；设为0不删除；单页自动跳过
              </div>
            </n-tooltip>
          </n-space>
          
          <n-upload 
            :show-file-list="false" 
            :custom-request="handleFileUpload" 
            :accept="acceptedFileTypes" 
            multiple
          >
            <n-upload-dragger>
              <div style="margin-bottom: 12px">
                <n-icon size="48" :depth="3">
                  <CloudUpload />
                </n-icon>
              </div>
              <n-text style="font-size: 16px">
                点击上传或拖拽文件到此区域
              </n-text>
              <n-p depth="3" style="margin: 8px 0 0 0">
                文件将被转换为PDF并删除末尾指定页数后供下载；若设置为0则不删除页数
              </n-p>
            </n-upload-dragger>
          </n-upload>
        </n-spin>
      </n-card>
    </n-gi>

    <!-- 操作按钮 -->
    <n-gi class="main-part" v-if="mainStore.processedFiles.length > 0">
      <n-flex justify="space-between" align="center">
        <div>
          <n-text>处理文件: {{ mainStore.processedFiles.length }} 个</n-text>
          <n-button size="small" style="margin-left: 8px;" @click="processLoadingVisible = true" secondary>
            处理进度
          </n-button>
        </div>
        <n-button type="primary" @click="clearProcessedFiles" secondary>
          清空列表
        </n-button>
      </n-flex>
    </n-gi>

    <!-- 处理结果列表 -->
    <n-gi class="main-part processed-files" v-if="mainStore.processedFiles.length > 0">
      <n-card title="处理结果">
        <n-list>
          <n-list-item v-for="file in mainStore.processedFiles" :key="file.fileId" :class="(file.gpoUpdateResult && file.gpoUpdateResult.status !== 200) ? 'row-error' : ''">
            <template #prefix>
              <n-avatar size="36">
                <n-icon size="24">
                  <component :is="getFileIcon(file.processedFileName)" />
                </n-icon>
              </n-avatar>
            </template>
            
            <n-thing>
              <template #header>
                <div class="file-item-header">
                  <div class="file-item-title">
                    <span
                      class="file-name"
                      :title="(file.dffInfo && file.dffInfo.detail && file.dffInfo.detail.headers && file.dffInfo.detail.headers.orderNo) ? file.dffInfo.detail.headers.orderNo : (file.originalName ? file.originalName.replace(/\.[^/.]+$/, '') : '')"
                    >
                      {{ (file.dffInfo && file.dffInfo.detail && file.dffInfo.detail.headers && file.dffInfo.detail.headers.orderNo) ? file.dffInfo.detail.headers.orderNo : (file.originalName ? file.originalName.replace(/\.[^/.]+$/, '') : '') }}
                    </span>
                    <n-tag v-if="file.dffInfo" :type="file.dffInfo.type === 'order' ? 'success' : 'info'" size="small">
                      {{ file.dffInfo.type === 'order' ? 'Order' : 'Enquiry' }}
                    </n-tag>
                    <n-tag v-if="file.pageDeleteSkipped" size="small" type="warning">单页文件不删页</n-tag>
                  </div>
                  <div class="file-item-actions">
                    <n-button 
                      v-if="mainStore.isAdmin && file.productDffResponse && file.productDffResponse.length > 0 && file.processedFilePath"
                      type="warning" 
                      size="small" 
                      @click="runWithProgress(file)"
                      :loading="file.trfApiLoading"
                      secondary
                    >
                      TRF to GPO
                    </n-button>
                  </div>
                </div>
              </template>
              <template #header-extra>
                <div class="header-extra-right">
                  <n-tooltip v-if="file.gpoUpdateResult" placement="top">
                    <template #trigger>
                      <n-tag size="small" :type="file.gpoUpdateResult.status === 200 ? 'success' : 'error'">
                        {{ file.gpoUpdateResult.status === 200 ? 'TRF to GPO成功' : 'TRF to GPO未成功' }}
                      </n-tag>
                    </template>
                  <div style="font-size: 12px; line-height: 1.5;">
                    <div>状态: {{ file.gpoUpdateResult.status }}</div>
                    <div v-if="file.gpoUpdateResult.message">响应: {{ file.gpoUpdateResult.message }}</div>
                    <div v-if="file.gpoUpdateResult.status !== 200">单号: {{ (file.dffInfo && file.dffInfo.detail && file.dffInfo.detail.headers && file.dffInfo.detail.headers.orderNo) ? file.dffInfo.detail.headers.orderNo : (file.originalName ? file.originalName.replace(/\.[^/.]+$/, '') : '') }}</div>
                  </div>
                </n-tooltip>
              </div>
              </template>
              <template #description>
                <div>
                  <template v-if="mainStore.isAdmin">
                    <n-space wrap size="small" class="compact-tags">
                      <n-tag size="small" type="default">{{ file.processedFileName }}</n-tag>
                      <n-tag v-if="file.dffInfo && !file.dffInfo.error" size="small" type="success">DFF已获取</n-tag>
                      <n-tag v-else size="small" type="warning">DFF缺失</n-tag>
                      <n-tag v-if="file.trfApiResult" size="small" type="success">TRF已识别</n-tag>
                      <n-tag v-else size="small" type="default">TRF未识别</n-tag>
                      <n-tooltip v-if="file.gpoUpdateResult" placement="top">
                        <template #trigger>
                          <n-tag size="small" :type="file.gpoUpdateResult.status === 200 ? 'success' : 'error'">
                            {{ file.gpoUpdateResult.status === 200 ? 'GPO更新成功' : 'GPO更新失败' }}
                          </n-tag>
                        </template>
                        <n-scrollbar style="max-height: 240px; max-width: 420px;">
                          <div style="font-size: 12px; line-height: 1.5;">
                            <div v-for="(val, key) in file.gpoUpdateResult" :key="key">
                              {{ key }}: {{ formatPlainValue(val) }}
                            </div>
                          </div>
                        </n-scrollbar>
                      </n-tooltip>
                    </n-space>
                  </template>
                  <template v-else></template>
                </div>
              </template>
              <template #action v-if="mainStore.isAdmin">
                <n-space>
                  <n-button 
                    v-if="mainStore.isAdmin"
                    type="primary" 
                    size="small" 
                    @click="downloadFile(file)"
                    :render-icon="() => h(Download)"
                  >
                    下载PDF
                  </n-button>
                  <n-button 
                    v-if="file.dffInfo && !file.dffInfo.error && mainStore.isAdmin" 
                    type="info" 
                    size="small" 
                    @click="showDffInfo(file.dffInfo, file.dffTemplateInfo, file.productDffResponse, file.samplesDffResponse)"
                    secondary
                  >
                    查看DFF
                  </n-button>
                  <n-button 
                    v-if="file.dffInfo && file.dffInfo.error" 
                    type="error" 
                    size="small" 
                    @click="showDffError(file.dffInfo.error, file.originalName)"
                    secondary
                  >
                    查看错误详情
                  </n-button>
                  <n-button 
                    v-if="file.powerBiStats && mainStore.isAdmin" 
                    type="warning" 
                    size="small" 
                    @click="showPbiStats(file.powerBiStats, file.originalName)"
                    secondary
                  >
                    查看PBI数据
                  </n-button>
                  <n-button 
                    v-if="file.productDffResponse && file.productDffResponse.length > 0 && mainStore.isAdmin" 
                    type="success" 
                    size="small" 
                    @click="downloadCsv(file)"
                    secondary
                  >
                    下载CSV
                  </n-button>
                  <n-button 
                    v-if="file.productDffResponse && file.productDffResponse.length > 0 && file.processedFilePath && mainStore.isAdmin" 
                    type="warning" 
                    size="small" 
                    @click="callTrfApi(file)"
                    :loading="file.trfApiLoading"
                    secondary
                  >
                    TRF to GPO
                  </n-button>
                  <n-button 
                    v-if="file.trfApiResult && mainStore.isAdmin" 
                    type="info" 
                    size="small" 
                    @click="showTrfApiResult(file)"
                    secondary
                  >
                    TRF识别结果
                  </n-button>
                  <n-button 
                    v-if="file.trfRequestData && mainStore.isSystemAdmin" 
                    type="info" 
                    size="small" 
                    @click="showTrfRequest(file)"
                    secondary
                  >
                    TRF请求体
                  </n-button>
                  <n-button 
                    v-if="file.gpoRequestData && mainStore.isAdmin" 
                    type="info" 
                    size="small" 
                    @click="showGpoRequest(file)"
                    secondary
                  >
                    GPO请求体
                  </n-button>
            
                </n-space>
              </template>
            </n-thing>
          </n-list-item>
        </n-list>
      </n-card>
    </n-gi>




  </n-grid>



  <!-- DFF信息模态框 -->
  <n-modal v-model:show="showDffModal" preset="card" :title="selectedDffInfo?.title || (selectedDffInfo?.type === 'pbi-stats' ? 'PBI统计数据详情' : selectedDffInfo?.type === 'dff-error' ? 'DFF查询错误详情' : 'DFF信息详情')" style="width: 80%; max-width: 1000px;">
    <div v-if="selectedDffInfo">
      <!-- DFF错误信息显示 -->
      <div v-if="selectedDffInfo.type === 'dff-error'">
        <n-alert type="error" :title="selectedDffInfo.error.message" show-icon>
          <template #icon>
            <n-icon :component="AlertCircle" />
          </template>
          <div style="margin-top: 12px;">
            <n-descriptions :column="1" bordered>
              <n-descriptions-item label="错误类型">
                <n-tag type="error">{{ selectedDffInfo.error.type }}</n-tag>
              </n-descriptions-item>
              <n-descriptions-item label="文件名">
                {{ selectedDffInfo.fileName }}
              </n-descriptions-item>
              <n-descriptions-item label="详细说明">
                {{ selectedDffInfo.error.details }}
              </n-descriptions-item>
              <n-descriptions-item v-if="selectedDffInfo.error.orderNo" label="订单号">
                {{ selectedDffInfo.error.orderNo }}
              </n-descriptions-item>
              <n-descriptions-item v-if="selectedDffInfo.error.enquiryNo" label="询价单号">
                {{ selectedDffInfo.error.enquiryNo }}
              </n-descriptions-item>
              <n-descriptions-item v-if="selectedDffInfo.error.originalError" label="系统错误">
                <n-code :code="selectedDffInfo.error.originalError" language="text" />
              </n-descriptions-item>
            </n-descriptions>
          </div>
          
          <div style="margin-top: 16px;">
            <n-alert type="info" title="解决建议" show-icon>
              <ul style="margin: 8px 0; padding-left: 20px;">
                <li v-if="selectedDffInfo.error.type === 'ORDER_NOT_FOUND'">
                  检查订单号是否正确输入
                </li>
                <li v-if="selectedDffInfo.error.type === 'ORDER_NOT_FOUND'">
                  确认订单是否已在GPO系统中创建
                </li>
                <li v-if="selectedDffInfo.error.type === 'ENQUIRY_NOT_FOUND'">
                  检查询价单号是否正确输入
                </li>
                <li v-if="selectedDffInfo.error.type === 'ENQUIRY_NOT_FOUND'">
                  确认询价单是否已在GPO系统中创建
                </li>
                <li v-if="selectedDffInfo.error.type === 'MISSING_TOKEN'">
                  请重新登录系统获取有效的认证令牌
                </li>
                <li v-if="selectedDffInfo.error.type === 'INVALID_FILENAME'">
                  请按照正确的命名规范重命名文件
                </li>
                <li v-if="selectedDffInfo.error.type === 'API_ERROR'">
                  请稍后重试，如问题持续存在请联系系统管理员
                </li>
                <li>如需帮助，请联系技术支持团队</li>
              </ul>
            </n-alert>
          </div>
        </n-alert>
      </div>
      
      <!-- TRF结果显示 -->
      <div v-if="selectedDffInfo.type === 'trf-result'">
        <n-scrollbar style="max-height: 600px;">
          <pre style="white-space: pre-wrap; font-family: monospace; font-size: 14px; line-height: 1.5;">{{ selectedDffInfo.content }}</pre>
        </n-scrollbar>
      </div>
      <div v-else-if="selectedDffInfo.type === 'gpo-request'">
        <n-scrollbar style="max-height: 600px;">
          <n-code :code="selectedDffInfo.content" language="json" :hljs="hljs" />
        </n-scrollbar>
      </div>
      <div v-else-if="selectedDffInfo.type === 'trf-request'">
        <n-scrollbar style="max-height: 600px;">
          <n-code :code="selectedDffInfo.content" language="json" :hljs="hljs" />
        </n-scrollbar>
      </div>
      
      <!-- PBI统计数据显示 -->
      <div v-else-if="selectedDffInfo.type === 'pbi-stats'">
        <n-descriptions :column="1" bordered>
          <n-descriptions-item label="文件名">
            {{ selectedDffInfo.fileName }}
          </n-descriptions-item>
          <n-descriptions-item label="统计状态">
            <n-tag :type="selectedDffInfo.content.success ? 'success' : 'error'">
              {{ selectedDffInfo.content.success ? '成功' : '失败' }}
            </n-tag>
          </n-descriptions-item>
        </n-descriptions>
        
        <n-divider />
        
        <n-tabs type="line" animated>
          <n-tab-pane name="request" tab="请求数据">
            <n-scrollbar style="max-height: 400px;">
              <n-code :code="formatDffData(selectedDffInfo.content.requestData)" language="json" :hljs="hljs" />
            </n-scrollbar>
          </n-tab-pane>
          <n-tab-pane name="response" tab="响应数据" v-if="selectedDffInfo.content.responseData">
            <n-scrollbar style="max-height: 400px;">
              <n-code :code="formatDffData(selectedDffInfo.content.responseData)" language="json" :hljs="hljs" />
            </n-scrollbar>
          </n-tab-pane>
          <n-tab-pane name="error" tab="错误信息" v-if="selectedDffInfo.content.error">
            <n-scrollbar style="max-height: 400px;">
              <n-alert type="error" :title="selectedDffInfo.content.error.message || '未知错误'">
                <template v-if="selectedDffInfo.content.error.details">
                  <n-code :code="formatDffData(selectedDffInfo.content.error.details)" language="json" :hljs="hljs" />
                </template>
              </n-alert>
            </n-scrollbar>
          </n-tab-pane>
        </n-tabs>
      </div>
      
      <!-- DFF信息显示 -->
      <div v-else>
        <n-descriptions :column="2" bordered>
          <n-descriptions-item label="类型">
            <n-tag :type="selectedDffInfo.type === 'order' ? 'success' : 'info'">
              {{ selectedDffInfo.type === 'order' ? 'Order' : 'Enquiry' }}
            </n-tag>
          </n-descriptions-item>
          <n-descriptions-item label="ID">
            {{ selectedDffInfo.id }}
          </n-descriptions-item>
        </n-descriptions>
        
        <n-divider />
        
        <n-tabs type="line" animated>
          <n-tab-pane name="detail" tab="详细信息">
            <n-scrollbar style="max-height: 400px;">
              <n-code :code="formatDffData(selectedDffInfo.detail)" language="json" :hljs="hljs" />
            </n-scrollbar>
          </n-tab-pane>
          <n-tab-pane name="sample" tab="样品数据" v-if="selectedDffInfo.sampleData">
            <n-scrollbar style="max-height: 400px;">
              <n-code :code="formatDffData(selectedDffInfo.sampleData)" language="json" :hljs="hljs" />
            </n-scrollbar>
          </n-tab-pane>
          <n-tab-pane name="template" tab="DFF模板" v-if="selectedDffInfo.templateInfo">
            <n-tabs type="segment" animated>
              <n-tab-pane name="productTemplate" tab="产品模板DFF查询响应" v-if="selectedDffInfo.productDffResponse">
                <n-scrollbar style="max-height: 400px;">
                  <n-code :code="formatDffData(selectedDffInfo.productDffResponse)" language="json" :hljs="hljs" />
                </n-scrollbar>
              </n-tab-pane>
              <n-tab-pane name="productSamplesTemplate" tab="样品模板DFF查询响应" v-if="selectedDffInfo.samplesDffResponse">
                <n-scrollbar style="max-height: 400px;">
                  <n-code :code="formatDffData(selectedDffInfo.samplesDffResponse)" language="json" :hljs="hljs" />
                </n-scrollbar>
              </n-tab-pane>
            </n-tabs>
          </n-tab-pane>
        </n-tabs>
      </div>
    </div>
  </n-modal>

  <n-modal v-model:show="processLoadingVisible" preset="card" title="执行进度" style="width: 60%; max-width: 800px;">
    <n-list>
      <n-list-item v-for="(p, fid) in processingProgress" :key="fid">
        <div style="display:flex; align-items:center; justify-content: space-between; margin-bottom: 8px;">
          <n-text>{{ p.orderNo }}</n-text>
          <n-tag :type="p.statuses[5] === 'finish' ? 'success' : (p.statuses.some(s => s === 'error') ? 'error' : 'warning')" size="small">
            {{ p.statuses[5] === 'finish' ? '完成' : (p.statuses.some(s => s === 'error') ? '失败' : '处理中') }}
          </n-tag>
        </div>
        <n-steps size="small">
          <n-step v-for="(label, i) in p.labels" :key="i" :title="label" :status="p.statuses[i]" />
        </n-steps>
      </n-list-item>
    </n-list>
  </n-modal>



</template>

<style lang="stylus">
.main-part
  margin-bottom: 16px

.processed-files
  max-height: 400px
  overflow-y: auto

.file-item-header
  display: flex
  align-items: center
  justify-content: space-between
  width: 100%

.file-item-title
  display: flex
  align-items: center
  gap: 8px
  flex: 1

.file-name
  display: block
  flex: 1
  min-width: 0
  white-space: normal
  overflow: visible
  word-break: break-word
  overflow-wrap: anywhere

.file-item-actions
  display: flex
  align-items: center
  gap: 8px
  margin-left: 16px

.file-status-tag
  margin-left: 4px
  margin-right: 12px

.n-list-item
  padding: 10px 0
  border-bottom: 1px solid #efefef
  transition: border-color 0.3s ease
  &:hover
    background-color: rgba(0,0,0,0.02)

.row-error
  background-color: #fff1f0
  border-left: 3px solid #d03050

.row-error:hover
  background-color: #ffecee

body.dark .row-error
  background-color: rgba(208,48,80,0.12)
  border-left: 3px solid #d03050
  
  &:last-child
    border-bottom: none

// 深色主题下的列表项样式
body.dark .n-list-item
  border-bottom-color: #404040

.n-list
  background-color: transparent  

// 优化卡片样式，与新布局保持一致
.n-card
  border-radius: 8px
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08)
  transition: box-shadow 0.3s ease, background-color 0.3s ease, border-color 0.3s ease
  border: 1px solid #e8e8e8
  
  &:hover
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12)

// 深色主题下的卡片样式
body.dark .n-card
  background-color: #2d2d2d
  border-color: #404040
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3)
  
  &:hover
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.4)

// 优化上传区域样式
.n-upload-dragger
  border-radius: 8px
  border: 2px dashed #d9d9d9
  transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1)
  transform: scale(1)
  
  &:hover
    border-color: #1890ff
    background-color: rgba(24, 144, 255, 0.02)
    transform: scale(1.02)
    box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15)

// 深色主题下的上传区域样式
body.dark .n-upload-dragger
  border-color: #555555
  background-color: #2d2d2d
  
  &:hover
    border-color: #40a9ff
    background-color: rgba(64, 169, 255, 0.1)
    transform: scale(1.02)
    box-shadow: 0 4px 12px rgba(64, 169, 255, 0.2)

// 优化按钮间距
.n-space
  gap: 8px !important

.compact-tags :deep(.n-tag)
  border-radius: 12px
  font-size: 12px
  padding: 0 8px

.header-extra-right
  margin-right: 8px
</style>
